<?php

/**
 * @author Lam Vu Nhat
 * @copyright 2011
 */
class Muare_Importer_vBulletin extends XFCP_Muare_Importer_vBulletin
{
	protected function _importUser(array $user, array $options)
	{
		if ($this->_groupMap === null)
		{
			$this->_groupMap = $this->_importModel->getImportContentMap('userGroup');
		}

		if ($this->_userFieldMap === null)
		{
			$this->_userFieldMap = $this->_importModel->getImportContentMap('userField');
		}

		$user['options'] = intval($user['options']);

		$import = array(
			'username' => $this->_convertToUtf8($user['username'], true),
			'email' => $this->_convertToUtf8($user['email']),
			'user_group_id' => $this->_mapLookUp($this->_groupMap, $user['usergroupid'], XenForo_Model_User::$defaultRegisteredGroupId),
			'secondary_group_ids' => $this->_mapLookUpList($this->_groupMap, explode(',', $user['membergroupids'])),
			'authentication' => array(
				'scheme_class' => 'XenForo_Authentication_vBulletin',
				'data' => array('hash' => $user['password'], 'salt' => $user['salt'])
			),
			'homepage' => $this->_convertToUtf8($user['homepage']),
			'last_activity' => $user['lastactivity'],
			'register_date' => $user['joindate'],
			'ip' => $user['ipaddress'],
			'message_count' => $user['posts'],
			'is_admin' => $user['is_admin'],
			'is_banned' => $user['is_banned'],
			'signature' => $this->_convertToUtf8($user['signature']),
			'timezone' => $this->_importModel->resolveTimeZoneOffset($user['timezoneoffset'], $user['options'] & 64),
			// 64 = dstauto
			'content_show_signature' => (($user['options'] & 1) ? 1 : 0),
			// 1 = showsignatures
			'receive_admin_email' => (($user['options'] & 16) ? 1 : 0), // 16 = adminemail
		);

		// TODO: other options that can be imported? show sigs, etc?

		if ($user['customtitle'])
		{
			$import['custom_title'] = $this->_convertToUtf8($user['usertitle']);
			if ($user['customtitle'] == 2) // admin set
			{
				$import['custom_title'] = htmlspecialchars_decode($import['custom_title']);
				$import['custom_title'] = preg_replace('#<br\s*/?>#i', ', ', $import['custom_title']);
				$import['custom_title'] = strip_tags($import['custom_title']);
			}
		}

		if (!($user['options'] & 2048)) // 2048 = receivepm
		{
			$import['allow_send_personal_conversation'] = 'none';
		}
		else if ($user['options'] & 131072) // 131072 = receivepmbuddies
		{
			$import['allow_send_personal_conversation'] = 'followed';
		}

		if (!($user['options'] & 8388608)) // 8388608 = vm_enable
		{
			$import['allow_post_profile'] = 'none';
		}
		else if ($user['options'] & 16777216) // 16777216 = vm_contactonly
		{
			$import['allow_post_profile'] = 'followed';
		}

		if ($user['birthday'])
		{
			$parts = explode('-', $user['birthday']);
			if (count($parts) == 3)
			{
				$import['dob_day'] = $parts[1];
				$import['dob_month'] = $parts[0];
				$import['dob_year'] = $parts[2];
			}
		}

		// try to give users without an avatar that have actually posted a gravatar
		if (!empty($options['gravatar']))
		{
			if (!$user['has_custom_avatar'] && $user['email'] && $user['lastpost']
				&& XenForo_Model_Avatar::gravatarExists($user['email']))
			{
				$import['gravatar'] = $import['email'];
			}
		}

		$import['about'] = '';
		if (isset($user['field1']))
		{
			$import['about'] .= $this->_convertToUtf8($user['field1']) . "\n\n";
		}
		if (isset($user['field3']))
		{
			$import['about'] .= $this->_convertToUtf8($user['field3']) . "\n\n";
		}
		$import['about'] = trim($import['about']);

		if (isset($user['field2']))
		{
			$import['location'] = $this->_convertToUtf8($user['field2']);
		}
		if (isset($user['field4']))
		{
			$import['occupation'] = $this->_convertToUtf8($user['field4']);
		}

		switch ($user['usergroupid'])
		{
			case 3:
				$import['user_state'] = 'email_confirm';
				break;
			case 4:
				$import['user_state'] = 'moderated';
				break;
			default:
				$import['user_state'] = 'valid';
		}

		switch ($user['autosubscribe'])
		{
			case -1:
				$import['default_watch_state'] = '';
				break;
			case 0:
				$import['default_watch_state'] = 'watch_no_email';
				break;
			default:
				$import['default_watch_state'] = 'watch_email';
		}

		switch ($user['showbirthday'])
		{
			case 0:
				$import['show_dob_year'] = 0;
				$import['show_dob_date'] = 0;
				break;
			case 1:
				$import['show_dob_year'] = 1;
				$import['show_dob_date'] = 0;
				break;
			case 2:
				$import['show_dob_year'] = 1;
				$import['show_dob_date'] = 1;
				break;
			case 3:
				$import['show_dob_year'] = 0;
				$import['show_dob_date'] = 1;
				break;
		}

		// custom user fields
		$userFieldDefinitions = $this->_importModel->getUserFieldDefinitions();

		// Add facebook as icq
		if (isset($userFieldDefinitions['facebook']))
		{
			$import[XenForo_Model_Import::USER_FIELD_KEY]['facebook'] = $this->_convertToUtf8($user['icq']);
		}

		// Add twitter as msn
		if (isset($userFieldDefinitions['twitter']))
		{
			$import[XenForo_Model_Import::USER_FIELD_KEY]['facebook'] = $this->_convertToUtf8($user['msn']);
		}

		foreach (array('yahoo', 'skype') AS $identityType)
		{
			if (isset($userFieldDefinitions[$identityType]))
			{
				$import[XenForo_Model_Import::USER_FIELD_KEY][$identityType] = $this->_convertToUtf8($user[$identityType]);
			}
		}

		$userFieldLookups = $this->_session->getExtraData('userFieldLookups');

		foreach ($this->_userFieldMap AS $oldFieldId => $newFieldId)
		{
			if (!isset($userFieldDefinitions[$newFieldId]))
			{
				continue;
			}

			$userFieldValue = '';

			if ($user["field$oldFieldId"] !== '')
			{
				if (isset($userFieldLookups[$oldFieldId]))
				{
					$fieldInfo = $userFieldLookups[$oldFieldId];

					// use the lookup info to resolve the value
					if ($fieldInfo['multiple'])
					{
						$userFieldValue = array();

						foreach ($fieldInfo['choices'] AS $bitValue => $stringValue)
						{
							if ($user["field$oldFieldId"] & $bitValue)
							{
								$userFieldValue[$stringValue] = $stringValue;
							}
						}
					}
					else
					{
						$fieldChoiceId = $this->_convertToUtf8($user["field$oldFieldId"]);

						if (isset($fieldInfo['choices'][$fieldChoiceId]))
						{
							$userFieldValue = $fieldInfo['choices'][$fieldChoiceId];
						}
					}
				}
				else
				{
					// set the field value directly
					$userFieldValue = $this->_convertToUtf8($user["field$oldFieldId"]);
				}
			}

			$import[XenForo_Model_Import::USER_FIELD_KEY][$newFieldId] = $userFieldValue;
		}

		if ($user['is_admin'] && $user['admin_permissions'])
		{
			$user['admin_permissions'] = intval($user['admin_permissions']);

			$aPerms = array();
			if ($user['admin_permissions'] & 4)
			{
				$aPerms[] = 'option';
			}
			if ($user['admin_permissions'] & 8)
			{
				$aPerms[] = 'style';
			}
			if ($user['admin_permissions'] & 16)
			{
				$aPerms[] = 'language';
			}
			if ($user['admin_permissions'] & 32)
			{
				$aPerms[] = 'node';
			}
			if ($user['admin_permissions'] & 256)
			{
				$aPerms[] = 'user';
				$aPerms[] = 'ban';
				$aPerms[] = 'identityService';
				$aPerms[] = 'trophy';
				$aPerms[] = 'userUpgrade';
			}
			if ($user['admin_permissions'] & 512)
			{
				$aPerms[] = 'userGroup';
			} // actually, user permissions
			if ($user['admin_permissions'] & 4096)
			{
				$aPerms[] = 'bbCodeSmilie';
			}
			if ($user['admin_permissions'] & 8192)
			{
				$aPerms[] = 'cron';
			}
			if ($user['admin_permissions'] & 16384)
			{
				$aPerms[] = 'import';
				$aPerms[] = 'upgradeXenForo';
			}
			if ($user['admin_permissions'] & 65536)
			{
				$aPerms[] = 'addOn';
			}

			$import['admin_permissions'] = $aPerms;
		}

		$importedUserId = $this->_importModel->importUser($user['userid'], $import, $failedKey);
		if ($importedUserId)
		{
			if ($user['is_banned'])
			{
				$this->_importModel->importBan(
					array(
						'user_id' => $importedUserId,
						'ban_user_id' => $this->_importModel->mapUserId($user['ban_user_id'], 0),
						'ban_date' => $user['ban_date'],
						'end_date' => $user['ban_end_date'],
						'user_reason' => $this->_convertToUtf8($user['ban_reason'])
					));
			}

			if ($user['is_super_moderator'])
			{
				$this->_session->setExtraData('superMods', $user['userid'], $importedUserId);
			}

			if ($user['buddylist'])
			{
				$buddyIds = array_slice(explode(' ', $user['buddylist']), 0, 1000);
				$buddyIds = $this->_importModel->getImportContentMap('user', $buddyIds);
				$this->_importModel->importFollowing($importedUserId, $buddyIds);
			}
			// TODO: import ignore list
		}
		else if ($failedKey)
		{
			$this->_session->setExtraData('userFailed', $user['userid'], $failedKey);
		}

		return $importedUserId;
	}

	public function stepAvatars($start, array $options)
	{
		$options = array_merge(
			array(
				'path' => isset($this->_config['avatarPath']) ? $this->_config['avatarPath'] : '',
				'limit' => 50,
				'max' => false
			), $options);

		$sDb = $this->_sourceDb;
		$prefix = $this->_prefix;

		/* @var $model XenForo_Model_Import */
		$model = $this->_importModel;

		if ($options['max'] === false)
		{
			$options['max'] = $sDb->fetchOne('
				SELECT MAX(userid)
				FROM ' . $prefix . 'customavatar
			');
		}

		$avatars = $sDb->fetchAll(
            $sDb->limit('
				SELECT customavatar.userid, user.avatarrevision
				FROM ' . $prefix . 'customavatar AS customavatar
				INNER JOIN ' . $prefix . 'user AS user ON (user.userid = customavatar.userid)
				WHERE customavatar.userid > ' . $sDb->quote($start) . '
				ORDER BY customavatar.userid
			', $options['limit']));
		if (!$avatars)
		{
			return true;
		}

		$userIdMap = $model->getUserIdsMapFromArray($avatars, 'userid');

		$next = 0;
		$total = 0;

		foreach ($avatars AS $avatar)
		{
			$next = $avatar['userid'];

			$newUserId = $this->_mapLookUp($userIdMap, $avatar['userid']);
			if (!$newUserId)
			{
				continue;
			}

			if (!$options['path'])
			{
				$fData = $sDb->fetchOne('
					SELECT filedata
					FROM ' . $prefix . 'customavatar
					WHERE userid = ' . $sDb->quote($avatar['userid']));
				if ($fData === '')
				{
					continue;
				}

				$avatarFile = tempnam(XenForo_Helper_File::getTempDir(), 'xf');
				if (!$avatarFile || !@file_put_contents($avatarFile, $fData))
				{
					continue;
				}

				$isTemp = true;
			}
			else
			{
				$avatarFileOrig = "$options[path]/avatar$avatar[userid]_$avatar[avatarrevision].gif";
				if (!file_exists($avatarFileOrig))
				{
					continue;
				}

				$avatarFile = tempnam(XenForo_Helper_File::getTempDir(), 'xf');
				copy($avatarFileOrig, $avatarFile);

				$isTemp = true;
			}

			if ($this->_importModel->importAvatar($avatar['userid'], $newUserId, $avatarFile))
			{
				$total++;
			}

			if ($isTemp)
			{
				@unlink($avatarFile);
			}
		}

		$this->_session->incrementStepImportTotal($total);

		return array(
			$next, $options, $this->_getProgressOutput($next, $options['max'])
		);
	}

	public function stepThreads($start, array $options)
	{
		$options = array_merge(
            array(
				'limit' => 100,
                'postDateStart' => 0,
                'postLimit' => 800,
                'max' => false
			), $options);

		$sDb = $this->_sourceDb;
		$prefix = $this->_prefix;

		/* @var $model XenForo_Model_Import */
		$model = $this->_importModel;

		if ($options['max'] === false)
		{
			$options['max'] = $sDb->fetchOne('
				SELECT MAX(threadid)
				FROM ' . $prefix . 'thread
			');
		}

        $dateCute = time() - 31536000;

		// pull threads from things we actually imported as forums
		$threads = $sDb->fetchAll(
            $sDb->limit('
				SELECT thread.*
				FROM ' . $prefix . 'thread AS thread FORCE INDEX (PRIMARY)
				INNER JOIN ' . $prefix . 'forum AS forum ON
					(thread.forumid = forum.forumid AND forum.link = \'\' AND forum.options & 4)
				WHERE thread.threadid >= ' . $sDb->quote($start) . '
                    AND thread.uptime >= ' . $dateCute . '
					AND thread.open <> 10
				ORDER BY thread.threadid
			', $options['limit']));
		if (!$threads)
		{
			return true;
		}

		$next = 0;
		$total = 0;
		$totalPosts = 0;

		$nodeMap = $model->getImportContentMap('node');
		$threadPrefixMap = $model->getImportContentMap('threadPrefix');

		XenForo_Db::beginTransaction();

		foreach ($threads AS $thread)
		{
			if (trim($thread['title']) === '')
			{
				continue;
			}

			$postDateStart = $options['postDateStart'];

			$next = $thread['threadid'] + 1; // uses >=, will be moved back down if need to continue
			$options['postDateStart'] = 0;

			$maxPosts = $options['postLimit'] - $totalPosts;
			if ($thread['archive_flag']) $postPrefix = 'archive_';
            else $postPrefix = $prefix;

			$posts = $sDb->fetchAll(
                $sDb->limit('
					SELECT post.*
					FROM ' . $postPrefix . 'post AS post
					WHERE post.threadid = ' . $sDb->quote($thread['threadid']) . '
						AND post.dateline > ' . $sDb->quote($postDateStart) . '
					ORDER BY post.dateline
				', $maxPosts));
			if (!$posts)
			{
				if ($postDateStart)
				{
					// continuing thread but it has no more posts
					$total++;
				}
				continue;
			}

			if ($postDateStart)
			{
				// continuing thread we already imported
				$threadId = $model->mapThreadId($thread['threadid']);

				$position = $this->_db->fetchOne('
					SELECT MAX(position)
					FROM xf_post
					WHERE thread_id = ?
				', $threadId);
			}
			else
			{
				$forumId = $this->_mapLookUp($nodeMap, $thread['forumid']);
				if (!$forumId)
				{
					continue;
				}

				if (trim($thread['postusername']) === '')
				{
					$thread['postusername'] = 'Guest';
				}

				$import = array(
					'title' => $this->_convertToUtf8($thread['title'], true),
					'node_id' => $forumId,
					'user_id' => $model->mapUserId($thread['postuserid'], 0),
					'username' => $this->_convertToUtf8($thread['postusername'], true),
					'discussion_open' => $thread['open'],
					'post_date' => $thread['dateline'],
					'reply_count' => $thread['replycount'],
					'view_count' => $thread['views'],
					'sticky' => $thread['sticky'],
					'last_post_date' => $thread['lastpost'],
					'last_post_username' => $this->_convertToUtf8($thread['lastposter'], true),
				);
				if (isset($thread['prefixid']))
				{
					$import['prefix_id'] = $this->_mapLookUp($threadPrefixMap, $thread['prefixid'], 0);
				}
				switch ($thread['visible'])
				{
					case 0:
						$import['discussion_state'] = 'moderated';
						break;
					case 2:
						$import['discussion_state'] = 'deleted';
						break;
					default:
						$import['discussion_state'] = 'visible';
						break;
				}

				$threadId = $model->importThread($thread['threadid'], $import);
				if (!$threadId)
				{
					continue;
				}

				$position = -1;

				$subs = $sDb->fetchPairs('
					SELECT userid, emailupdate
					FROM ' . $prefix . 'subscribethread
					WHERE threadid = ' . $sDb->quote($thread['threadid']));
				if ($subs)
				{
					$userIdMap = $model->getImportContentMap('user', array_keys($subs));
					foreach ($subs AS $userId => $emailUpdate)
					{
						$newUserId = $this->_mapLookUp($userIdMap, $userId);
						if (!$newUserId)
						{
							continue;
						}

						$model->importThreadWatch($newUserId, $threadId, ($emailUpdate ? 1 : 0));
					}
				}
			}

			if ($threadId)
			{
				$quotedPostIds = array();

				$threadTitleRegex = '#^(re:\s*)?' . preg_quote($thread['title'], '#') . '$#i';

				$userIdMap = $model->getUserIdsMapFromArray($posts, 'userid');

				foreach ($posts AS $i => $post)
				{
					if ($post['title'] !== '' && !preg_match($threadTitleRegex, $post['title']))
					{
						$post['pagetext'] = '[b]' . htmlspecialchars_decode($post['title']) . "[/b]\n\n" . ltrim($post['pagetext']);
					}

					if (trim($post['username']) === '')
					{
						$post['username'] = 'Guest';
					}

					$post['pagetext'] = $this->_convertToUtf8($post['pagetext']);

					$import = array(
						'thread_id' => $threadId,
						'user_id' => $this->_mapLookUp($userIdMap, $post['userid'], 0),
						'username' => $this->_convertToUtf8($post['username'], true),
						'post_date' => $post['dateline'],
						'message' => $post['pagetext'],
						'attach_count' => 0,
						'ip' => $post['ipaddress']
					);
					switch ($post['visible'])
					{
						case 0:
							$import['message_state'] = 'moderated';
							$import['position'] = $position;
							break;
						case 2:
							$import['message_state'] = 'deleted';
							$import['position'] = $position;
							break;
						default:
							$import['message_state'] = 'visible';
							$import['position'] = ++$position;
							break;
					}

					$post['xf_post_id'] = $model->importPost($post['postid'], $import);

					$options['postDateStart'] = $post['dateline'];
					$totalPosts++;

					if (stripos($post['pagetext'], '[quote=') !== false)
					{
						if (preg_match_all('/\[quote=("|\'|)(?P<username>[^;]*);\s*(?P<postid>\d+)\s*\1\]/siU',
							$post['pagetext'], $quotes, PREG_SET_ORDER))
						{
							$post['quotes'] = array();

							foreach ($quotes AS $quote)
							{
								$quotedPostId = intval($quote['postid']);

								$quotedPostIds[] = $quotedPostId;

								$post['quotes'][$quote[0]] = array(
									$quote['username'], $quotedPostId
								);
							}
						}
					}

					$posts[$i] = $post;
				}

				$postIdMap = (empty($quotedPostIds) ? array() : $model->getImportContentMap('post', $quotedPostIds));

				$db = XenForo_Application::getDb();

				foreach ($posts AS $post)
				{
					if (!empty($post['quotes']))
					{
						$postQuotesRewrite = $this->_rewriteQuotes($post['pagetext'], $post['quotes'], $postIdMap);

						if ($post['pagetext'] != $postQuotesRewrite)
						{
							$db->update('xf_post', array('message' => $postQuotesRewrite), 'post_id = ' . $db->quote($post['xf_post_id']));
						}
					}
				}
			}

			if (count($posts) < $maxPosts)
			{
				// done this thread
				$total++;
				$options['postDateStart'] = 0;
			}
			else
			{
				// not necessarily done the thread; need to pick it up next page
				break;
			}
		}

		if ($options['postDateStart'])
		{
			// not done this thread, need to continue with it
			$next--;
		}

		XenForo_Db::commit();

		$this->_session->incrementStepImportTotal($total);

		return array(
			$next, $options, $this->_getProgressOutput($next, $options['max'])
		);
	}
}
